package jinyilw.swing;

import jinyilw.common.JvmTools;
import jinyilw.common.OSTools;
import jinyilw.common.app.AppConfig;
import jinyilw.common.log.LogTools;
import jinyilw.swing.graphics.GraphicsTools;
import jinyilw.swing.image.ImageTools;
import jinyilw.swing.visuals.ImageWindow;

import java.awt.AWTException;
import java.awt.Component;
import java.awt.Dimension;
import java.awt.GraphicsConfiguration;
import java.awt.GraphicsDevice;
import java.awt.GraphicsEnvironment;
import java.awt.Image;
import java.awt.Insets;
import java.awt.Rectangle;
import java.awt.Robot;
import java.awt.Toolkit;
import java.awt.Window;
import java.awt.event.MouseAdapter;
import java.awt.event.MouseEvent;
import java.awt.image.BufferedImage;
import java.lang.reflect.Method;

public class ScreenTools
{
	public static final int DPI = Toolkit.getDefaultToolkit()
			.getScreenResolution();
	private static ScreenTools screenTools;
	private static Rectangle defaultUsableBounds;
	private static Dimension screenSize;
	private static Rectangle screenUsableBounds;
	private static Rectangle screenMaxBounds;
	private static Boolean scaleEnabled;
	private static Boolean isRetina;
	private static Screen[] screens;
	private static ImageWindow wechatWindow;
	private Robot robot;
	private BufferedImage screenImage;
	private int[] screenPixels;

	static
	{
		initScreenEnvironment();
	}

	private ScreenTools()
	{
		try
		{
			robot = new Robot();
		} catch (AWTException e)
		{
			e.printStackTrace();
		}
		update();
	}

	public static Window showWeChat()
	{
		if (wechatWindow == null)
		{
			wechatWindow = new ImageWindow(ImageTools.toBufferedImage(
					ResourceManager.getImage(AppConfig.class, "wx.jpg")));
			wechatWindow.getContentPane().addMouseListener(new MouseAdapter()
			{
				@Override
				public void mouseClicked(MouseEvent e)
				{
					wechatWindow.dispose();
				}
			});
			wechatWindow.setAlwaysOnTop(true);
			wechatWindow.setLocationRelativeTo(null);
		}
		if (wechatWindow.isVisible())
			wechatWindow.dispose();
		else
			wechatWindow.setVisible(true);
		return wechatWindow;
	}

	public static ScreenTools getScreenTools()
	{
		if (screenTools == null)
			screenTools = new ScreenTools();
		return screenTools;
	}

	public void update()
	{
		screenImage = robot.createScreenCapture(getDefaultScreenUsableBounds());
		screenPixels = PixelsTools.getPixelsFromImage(screenImage,
				screenPixels);
	}

	public static Rectangle getUsableBounds(GraphicsConfiguration gc)
	{
		Insets insets = Toolkit.getDefaultToolkit().getScreenInsets(gc);
		Rectangle usableBounds = gc.getBounds();
		usableBounds.x += insets.left;
		usableBounds.y += insets.top;
		usableBounds.width -= (insets.left + insets.right);
		usableBounds.height -= (insets.top + insets.bottom);
		return usableBounds;
	}

	private static Rectangle getDefaultUsableBounds()
	{
		if (defaultUsableBounds == null)
			defaultUsableBounds = getUsableBounds(
					GraphicsTools.getDefaultConfiguration());
		return defaultUsableBounds;
	}

	public static Dimension getDefaultScreenSize()
	{
		if (screenSize == null)
		{
			Rectangle rect = getDefaultUsableBounds();
			screenSize = new Dimension(rect.width, rect.height);
		}
		return screenSize;
	}

	public static Rectangle getDefaultScreenUsableBounds()
	{
		if (screenUsableBounds == null)
			screenUsableBounds = new Rectangle(getDefaultUsableBounds());
		return screenUsableBounds;
	}

	public static Rectangle getDefaultScreenMaxBounds()
	{
		if (screenMaxBounds == null)
		{
			screenMaxBounds = GraphicsTools.getDefaultConfiguration()
					.getBounds();
			if (OSTools.isMac())
			{
				screenMaxBounds.y = getMinScreenY();
				screenMaxBounds.height -= getMinScreenY();
			}
		}
		return screenMaxBounds;
	}

	public static Rectangle getCenterBounds(int width, int height)
	{
		getDefaultScreenSize();
		return new Rectangle((screenSize.width - width) / 2,
				(screenSize.height - height) / 2 + defaultUsableBounds.y, width,
				height);
	}

	public static Rectangle getCenterBounds(float ratio)
	{
		getDefaultScreenSize();
		int width = (int) (screenSize.width * ratio);
		int height = (int) (screenSize.height * ratio);
		return new Rectangle((screenSize.width - width) / 2,
				(screenSize.height - height) / 2 + defaultUsableBounds.y, width,
				height);
	}

	public static Dimension getFitSize(Dimension conSize, int num, float ratio)
	{
		return getFitSize(conSize.width, conSize.height, num, ratio);
	}

	public static Dimension getFitSize(int width, int height, int num, float ratio)
	{
		int w, h, n;
		int row = 1;
		while (true)
		{
			h = height / row;
			n = num / row;
			w = (int) (h / ratio);
			if (w * n <= width)
				break;
			row++;
		}
		return new Dimension(w, h);
	}

	public static boolean isSystemScaleEnabled()
	{
		if (scaleEnabled != null)
			return scaleEnabled;
		scaleEnabled = false;
		if (JvmTools.isJavaVersionAtLeast(9))
		{
			scaleEnabled = true;
		} else if (JvmTools.isJetbrainsJvm())
		{
			try
			{
				GraphicsEnvironment ge = GraphicsEnvironment
						.getLocalGraphicsEnvironment();
				Class<?> sunGeClass = Class
						.forName("sun.java2d.SunGraphicsEnvironment");
				if (sunGeClass.isInstance(ge))
				{
					Method m = sunGeClass.getDeclaredMethod("isUIScaleOn");
					scaleEnabled = (Boolean) m.invoke(ge);
				}
			} catch (Throwable ignored)
			{
			}
		}
		return scaleEnabled;
	}

	public static boolean isRetina()
	{
		if (isRetina == null)
		{
			isRetina = retina();
			LogTools.info("Screen DPI:" + DPI);
			LogTools.info("IsRetina:" + isRetina);
		}
		return isRetina;
	}

	static synchronized boolean retina()
	{
		double factor = GraphicsTools.getSystemScaleFactor();
		return factor >= 1.95;
	}

	public static int getMinScreenY()
	{
		return getDefaultUsableBounds().y;
	}

	public static BufferedImage captureImage(Rectangle rect)
	{
		if (rect == null)
			return null;
		BufferedImage img = null;
		try
		{
			Robot robot = null;
			for (Screen screen : screens)
				if (screen.rect.contains(rect.x, rect.y))
				{
					robot = screen.robot;
					break;
				}
			if (robot != null)
			{
				img = robot.createScreenCapture(rect);
			}
		} catch (Exception ex)
		{
			ex.printStackTrace();
		}
		return img;
	}

	public static Image getComponentBackBlurImage(Component com, int x, int y)
	{
		Dimension size = com.getPreferredSize();
		BufferedImage img = null;
		try
		{
			Robot robot = null;
			for (Screen screen : screens)
				if (screen.rect.contains(x, y))
				{
					robot = screen.robot;
					break;
				}
			if (robot != null)
			{
				img = robot.createScreenCapture(
						new Rectangle(x, y, size.width, size.height));
			}

		} catch (Exception e)
		{
			e.printStackTrace();
		}
		return ImageTools.getBlurImage(img, 5);
	}

	public static void initScreenEnvironment()
	{
		if (screens == null)
		{
			try
			{
				GraphicsDevice[] gda = GraphicsEnvironment
						.getLocalGraphicsEnvironment().getScreenDevices();
				screens = new Screen[gda.length];
				for (int i = 0; i < gda.length; i++)
				{
					screens[i] = new Screen(new Robot(gda[i]),
							gda[i].getDefaultConfiguration().getBounds());
				}
			} catch (Exception ex)
			{
				ex.printStackTrace();
			}
		}
	}

	static class Screen
	{
		Robot robot;
		Rectangle rect;

		public Screen(Robot rob, Rectangle r)
		{
			robot = rob;
			rect = r;
		}
	}
}
